package com.bsj.power.system.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bsj.power.common.config.cached.PathCached;
import com.bsj.power.common.config.cached.RedisCached;
import com.bsj.power.common.config.exception.ApiException;
import com.bsj.power.common.config.global.JsonResult;
import com.bsj.power.common.config.global.JsonResultEnum;
import com.bsj.power.common.config.redis.RedisConstant;
import com.bsj.power.common.constant.NumericalConstants;
import com.bsj.power.common.def.dto.personGroup.PersonGroupDTO;
import com.bsj.power.common.def.dto.personGroup.PersonGroupSearchDTO;
import com.bsj.power.common.def.entity.job.WorkPersonnel;
import com.bsj.power.common.def.entity.path.Path;
import com.bsj.power.common.def.entity.personGroup.PersonGroup;
import com.bsj.power.common.def.entity.personGroup.PersonGroupPath;
import com.bsj.power.common.def.entity.personnel.Personnel;
import com.bsj.power.common.def.entity.sys.SystemConfig;
import com.bsj.power.common.def.entity.user.User;
import com.bsj.power.common.def.vo.PersonGroupVO;
import com.bsj.power.common.def.vo.pls.PathVO;
import com.bsj.power.common.mapper.*;
import com.bsj.power.common.util.DateUtils;
import com.bsj.power.common.util.ParamCheckUtil;
import com.bsj.power.system.service.PersonGroupService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author LiJiaXin
 * @version 1.0.0
 * @description PersonGroupServiceImpl
 * @time 2024/9/7 10:08
 */
@Service
public class PersonGroupServiceImpl implements PersonGroupService {

    @Resource
    private PersonGroupMapper personGroupMapper;

    @Resource
    private UserMapper userMapper;

    @Resource
    private WorkPersonnelMapper workPersonnelMapper;

    @Resource
    private PersonGroupPathMapper personGroupPathMapper;

    @Resource
    private PersonnelMapper personnelMapper;

    @Autowired
    private RedisCached redisCached;

    @Autowired
    private PathCached pathCached;

    /**
     * 添加人员组
     *
     * @param personGroupDTO
     * @return com.bsj.power.common.config.global.JsonResult
     * @author ljx
     * @time 2024/9/7 10:56
     */
    @Override
    @Transactional
    public JsonResult addPersonGroup(PersonGroupDTO personGroupDTO) {
        PersonGroup personGroup = new PersonGroup();
        paramCheck(personGroupDTO, personGroup);
        Integer groupType = personGroupDTO.getGroupType();
        List<Integer> pathIds = personGroupDTO.getPathIds();
        //父id默认为-1
        if (personGroupMapper.insert(personGroup) > NumericalConstants.ZERO) {
            //添加人员组与围栏的关系
            if (groupType == NumericalConstants.TWO) {
                Integer groupId = personGroup.getGroupId();
                if (!CollectionUtils.isEmpty(pathIds)) {
                    List<PersonGroupPath> personGroupPaths = pathIds.stream().map(pathId -> {
                        return new PersonGroupPath(groupId, pathId);
                    }).collect(Collectors.toList());
                    personGroupPathMapper.batchAdd(personGroupPaths);
                    personGroup.setPathList(pathIds);
                    redisCached.hset(RedisConstant.SUPER_GROUP_AUTH, groupId + "", JSON.toJSONString(personGroup));
                }
            }
            return JsonResult.success();
        } else {
            return JsonResult.fail();
        }
    }

    /**
     * 参数校验
     *
     * @param personGroupDTO
     * @param personGroup
     * @return void
     * @author ljx
     * @time 2024/9/15 16:09
     */
    private void paramCheck(PersonGroupDTO personGroupDTO, PersonGroup personGroup) {
        groupNameIsExist(personGroupDTO);
        BeanUtils.copyProperties(personGroupDTO, personGroup);
        Integer groupType = personGroupDTO.getGroupType();
        List<Integer> pathIds = personGroupDTO.getPathIds();
        if (groupType == NumericalConstants.TWO) {
            if (!CollectionUtils.isEmpty(pathIds)) {
                List<Path> paths = pathCached.hgetAllPathInfo();
                if (CollectionUtils.isEmpty(paths)) {
                    throw new ApiException(JsonResultEnum.PATH_NOT_EXIST);
                }
                List<Integer> pathIdList = paths.stream().map(Path::getPathId).collect(Collectors.toList());
                if (!pathIdList.containsAll(pathIds)) {
                    throw new ApiException(JsonResultEnum.PATH_NOT_EXIST);
                }
            }
            String startTime = personGroupDTO.getStartTime();
            String endTime = personGroupDTO.getEndTime();
            if (StringUtils.isNotBlank(startTime) && StringUtils.isBlank(endTime)) {
                throw new ApiException(JsonResultEnum.START_AND_END_TIME_IS_NULL);
            }
            if (StringUtils.isBlank(startTime) && StringUtils.isNotBlank(endTime)) {
                throw new ApiException(JsonResultEnum.START_AND_END_TIME_IS_NULL);
            }
            if (!StringUtils.isAllBlank(startTime, endTime)) {
                personGroup.setStartTime(DateUtils.strToDate(startTime));
                personGroup.setEndTime(DateUtils.strToDate(endTime));
            }
        }
    }

    /**
     * 删除人员组
     *
     * @param groupId
     * @return com.bsj.power.common.config.global.JsonResult
     * @author ljx
     * @time 2024/9/7 10:57
     */
    @Override
    @Transactional
    public JsonResult deletePersonGroup(Integer groupId) {
        ParamCheckUtil.isNull(groupId, JsonResultEnum.PARAM_ERROR);
        PersonGroup personGroup = personGroupMapper.selectById(groupId);
        ParamCheckUtil.isNull(personGroup, JsonResultEnum.PERSON_GROUP_EXIST);
        Integer groupType = personGroup.getGroupType();
        if (groupType.equals(NumericalConstants.ONE)) {
            if (userMapper.exists(Wrappers.<User>lambdaQuery().eq(User::getGroupId, groupId))) {
                throw new ApiException(JsonResultEnum.PERSON_GROUP_EXIST_USER);
            }
        } else {
            if (workPersonnelMapper.exists(Wrappers.<WorkPersonnel>lambdaQuery().eq(WorkPersonnel::getGroupId, groupId))) {
                throw new ApiException(JsonResultEnum.PERSON_GROUP_EXIST_PERSONNEL);
            }
            if (personnelMapper.exists(Wrappers.<Personnel>lambdaQuery().eq(Personnel::getGroupId, groupId))) {
                throw new ApiException(JsonResultEnum.PERSON_GROUP_EXIST_PERSONNEL);
            }
        }
        if (personGroupMapper.deleteById(groupId) > NumericalConstants.ZERO) {
            //删除与围栏的绑定关系
            personGroupPathMapper.delete(new QueryWrapper<PersonGroupPath>().lambda().eq(PersonGroupPath::getGroupId, groupId));
            //删除缓存
            redisCached.hdel(RedisConstant.SUPER_GROUP_AUTH, groupId + "");
            return JsonResult.success();
        } else {
            return JsonResult.fail();
        }
    }

    /**
     * 修改人员组
     *
     * @param personGroupDTO
     * @return com.bsj.power.common.config.global.JsonResult
     * @author ljx
     * @time 2024/9/7 10:57
     */
    @Override
    @Transactional
    public JsonResult updatePersonGroup(PersonGroupDTO personGroupDTO) {
        Integer groupId = personGroupDTO.getGroupId();
        ParamCheckUtil.isNull(groupId);
        PersonGroup oldPersonGroup = personGroupMapper.selectById(groupId);
        ParamCheckUtil.isNull(oldPersonGroup, JsonResultEnum.PERSON_GROUP_EXIST);
        Integer groupType = personGroupDTO.getGroupType();
        //组类型无法修改
        if (!groupType.equals(oldPersonGroup.getGroupType())) {
            return JsonResult.fail(JsonResultEnum.PERSON_GROUP_TYPE_CANNOT_UPDATE);
        }
        PersonGroup personGroup = new PersonGroup();
        paramCheck(personGroupDTO, personGroup);
        List<Integer> pathIds = personGroupDTO.getPathIds();
        LambdaUpdateWrapper<PersonGroup> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(PersonGroup::getGroupId, groupId);
        if (personGroup.getStartTime() == null || personGroup.getEndTime() == null) {
            updateWrapper.set(PersonGroup::getStartTime, null);
            updateWrapper.set(PersonGroup::getEndTime, null);
        }
        if (StringUtils.isBlank(personGroup.getRemark())) {
            updateWrapper.set(PersonGroup::getRemark, null);
        }
        if (personGroupMapper.update(personGroup, updateWrapper) > NumericalConstants.ZERO) {
            if (groupType == NumericalConstants.TWO) {
                //删除原先人员组与围栏的关系
                personGroupPathMapper.delete(new QueryWrapper<PersonGroupPath>().lambda().eq(PersonGroupPath::getGroupId, groupId));
                redisCached.hdel(RedisConstant.SUPER_GROUP_AUTH, groupId + "");
                if (!CollectionUtils.isEmpty(pathIds)) {
                    List<PersonGroupPath> personGroupPaths = pathIds.stream().map(pathId -> {
                        return new PersonGroupPath(groupId, pathId);
                    }).collect(Collectors.toList());
                    //添加新的关系
                    personGroupPathMapper.batchAdd(personGroupPaths);
                    personGroup.setPathList(pathIds);
                    redisCached.hset(RedisConstant.SUPER_GROUP_AUTH, groupId + "", JSON.toJSONString(personGroup));
                }
            }
            return JsonResult.success();
        } else {
            return JsonResult.fail();
        }
    }

    /**
     * 获取单个人员组
     *
     * @param groupId
     * @return com.bsj.power.common.def.entity.personGroup.PersonGroup
     * @author ljx
     * @time 2024/9/7 10:57
     */
    @Override
    public PersonGroup getPersonGroupById(Integer groupId) {
        ParamCheckUtil.isNull(groupId);
        PersonGroup personGroup = personGroupMapper.selectById(groupId);
        ParamCheckUtil.isNull(personGroup, JsonResultEnum.PERSON_GROUP_EXIST);
        List<PersonGroupPath> personGroupPaths = personGroupPathMapper.selectList(Wrappers.<PersonGroupPath>lambdaQuery().eq(PersonGroupPath::getGroupId, groupId));
        if (!CollectionUtils.isEmpty(personGroupPaths)) {
            List<Integer> pathIds = personGroupPaths.stream().map(PersonGroupPath::getPathId).collect(Collectors.toList());
            personGroup.setPathList(pathIds);
        }
        return personGroup;
    }

    /**
     * 人员组分页
     *
     * @param personGroupSearchDTO
     * @return com.bsj.power.common.config.global.JsonResult<java.util.List < com.bsj.power.common.def.vo.PersonGroupVO>>
     * @author ljx
     * @time 2024/9/7 10:57
     */
    @Override
    public JsonResult<List<PersonGroupVO>> pagePersonGroup(PersonGroupSearchDTO personGroupSearchDTO) {
        List<PersonGroupVO> personGroupVOS = new ArrayList<>();
        IPage<PersonGroup> page = new Page<>(personGroupSearchDTO.getPageNumber(), personGroupSearchDTO.getPageSize());
        QueryWrapper<PersonGroup> queryWrapper = new QueryWrapper<>();
        Integer groupType = personGroupSearchDTO.getGroupType();
        if (groupType != null) {
            queryWrapper.eq("group_type", groupType);
        }
        String groupName = personGroupSearchDTO.getGroupName();
        if (StringUtils.isNotBlank(groupName)) {
            queryWrapper.like("group_name", groupName);
        }
        IPage<PersonGroup> iPage = personGroupMapper.selectPage(page, queryWrapper);
        List<PersonGroup> personGroups = iPage.getRecords();
        if (!CollectionUtils.isEmpty(personGroups)) {
            Map<Integer, List<PathVO>> guoupMap = new HashMap<>();
            List<Integer> groupIds = personGroups.stream().map(PersonGroup::getGroupId).collect(Collectors.toList());
            //该批分组下的围栏
            List<PersonGroupPath> personGroupPaths = personGroupPathMapper.selectList(Wrappers.<PersonGroupPath>lambdaQuery().in(PersonGroupPath::getGroupId, groupIds));
            Map<Integer, List<Integer>> personGroupPathMap = new HashMap<>();
            if (!CollectionUtils.isEmpty(personGroupPaths)) {
                personGroupPaths.forEach(personGroupPath -> {
                    Integer groupId = personGroupPath.getGroupId();
                    Integer pathId = personGroupPath.getPathId();
                    List<Integer> pathIds = personGroupPathMap.get(groupId);
                    if (!CollectionUtils.isEmpty(pathIds)) {
                        pathIds.add(pathId);
                    } else {
                        pathIds = new LinkedList<>();
                        pathIds.add(pathId);
                    }
                    personGroupPathMap.put(groupId, pathIds);
                });
            }
            Map<Integer, Path> pathMap = null;
            if (!CollectionUtils.isEmpty(personGroupPaths)) {
                List<Integer> pathIds = personGroupPaths.stream().map(PersonGroupPath::getPathId).collect(Collectors.toList());
                List<Path> paths = pathCached.hgetPathInfoByIds(pathIds);
                if (!CollectionUtils.isEmpty(paths)) {
                    pathMap = paths.stream().collect(Collectors.toMap(Path::getPathId, Function.identity()));
                }
            }
            for (PersonGroup personGroup : personGroups) {
                PersonGroupVO personGroupVO = new PersonGroupVO();
                BeanUtils.copyProperties(personGroup, personGroupVO);
                List<PathVO> pathVOS = new LinkedList<>();
                if (!CollectionUtils.isEmpty(personGroupPathMap)) {
                    List<Integer> pathIds = personGroupPathMap.get(personGroup.getGroupId());
                    if (!CollectionUtils.isEmpty(pathIds)) {
                        for (Integer pathId : pathIds) {
                            if (!CollectionUtils.isEmpty(pathMap)) {
                                Path path = pathMap.get(pathId);
                                if (path != null) {
                                    pathVOS.add(new PathVO(path));
                                }
                            }
                        }
                    }
                }
                if (!CollectionUtils.isEmpty(pathVOS)) {
                    personGroupVO.setPaths(pathVOS);
                }
                personGroupVOS.add(personGroupVO);
            }
        }
        return JsonResult.success(personGroupVOS, iPage.getTotal());
    }

    /**
     * 组名是否存在
     *
     * @param personGroupDTO
     * @return void
     * @author ljx
     * @time 2024/9/7 11:01
     */
    private void groupNameIsExist(PersonGroupDTO personGroupDTO) {
        QueryWrapper<PersonGroup> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("group_name", personGroupDTO.getGroupName());
        queryWrapper.eq("group_type", personGroupDTO.getGroupType());
        Integer groupId = personGroupDTO.getGroupId();
        if (groupId != null) {
            queryWrapper.ne("group_id", personGroupDTO.getGroupId());
        }
        if (personGroupMapper.exists(queryWrapper)) {
            throw new ApiException(JsonResultEnum.PERSON_GROUP_NAME_EXIST);
        }
    }

}
